home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 41 / Amiga Format CD41 (1999-06)(Future Publishing)(GB)[!][issue 1999-07].iso / -seriously_amiga- / programming / other / gtlayout / source / lt_build.c < prev    next >
C/C++ Source or Header  |  1999-04-19  |  29KB  |  1,182 lines

  1. /*
  2. **    GadTools layout toolkit
  3. **
  4. **    Copyright © 1993-1998 by Olaf `Olsen' Barthel
  5. **        Freely distributable.
  6. **
  7. **    :ts=4
  8. */
  9.  
  10. #ifndef _GTLAYOUT_GLOBAL_H
  11. #include "gtlayout_global.h"
  12. #endif
  13.  
  14. /*****************************************************************************/
  15.  
  16. #include <stdarg.h>
  17.  
  18. /*****************************************************************************/
  19.  
  20. #include "Assert.h"
  21.  
  22. /*****************************************************************************/
  23.  
  24. /****** gtlayout.library/LT_BuildA ******************************************
  25. *
  26. *   NAME
  27. *    LT_BuildA -- turn the user interface specs into a window
  28. *                 and gadgets.
  29. *
  30. *   SYNOPSIS
  31. *    Window = LT_BuildA(Handle,Tags);
  32. *      D0                 A0    A1
  33. *
  34. *    struct Window *LT_BuildA(LayoutHandle *,struct TagItem *);
  35. *
  36. *    Window = LT_Build(Handle,...);
  37. *
  38. *    struct Window *LT_Build(LayoutHandle *,...);
  39. *
  40. *   FUNCTION
  41. *    This is the big one. After building up a user interface specification
  42. *    using LT_NewA() a call to LT_BuildA() will finally lay out the single
  43. *    user interface elements, open a window and put the gadgets, etc.
  44. *    inside.
  45. *
  46. *    The code tries to fit all the gadgets into the window, but if it
  47. *    runs out of space it will fall back to a different font and
  48. *    rescale the user interface objects to match it. It will first
  49. *    fall back onto the system default font. If unsuccessful it will
  50. *    as a last resort try to use topaz.font/8.
  51. *
  52. *    To make it easier to distinguish between different handles that
  53. *    share the same Window->UserPort, the Window->UserData pointer
  54. *    will point to the LayoutHandle that created it (V13).
  55. *
  56. *        NOTE: Earlier library releases did not support this feature,
  57. *            so be prepared to deal with Window->UserData == NULL.
  58. *
  59. *   INPUTS
  60. *    Handle - Pointer to a LayoutHandle structure.
  61. *
  62. *    Tags - Pointer to TagItem list controlling window
  63. *        and layout attributes.
  64. *
  65. *
  66. *    All the tag values given are passed straight away to OpenWindowTags(),
  67. *    see intuition.doc for more information.
  68. *
  69. *    In addition to this a number of private tag values are supported:
  70. *
  71. *    LAWN_Menu (struct Menu *) - The menu to attach to the window. The
  72. *        IDCMP flags will be updated to include IDCMP_MENUPICK if this
  73. *        tag is used.
  74. *
  75. *    LAWN_MenuTemplate (struct NewMenu *) - A list of filled-in
  76. *        NewMenu structures which will get passed straight through
  77. *        to LT_NewMenuTemplate(). If a menu could be created, it will
  78. *        be attached to the window. LT_DeleteHandle() will then later
  79. *        automatically dispose of the menu. Please note that the window
  80. *        may fail to open due to the menu layout going wrong. Separate
  81. *        calls to LT_NewMenuTemplate() and LT_Build() may be a better
  82. *        approach since it is easier to find out which process went
  83. *        wrong. You will find a pointer to the menu attached to the
  84. *        LayoutHandle in LayoutHandle->Menu. Please note that this
  85. *        entry only exists in LayoutHandles created by gtlayout.library
  86. *        v13 or higher. (V13)
  87. *
  88. *            NOTE: This tag effectively overrides LAWN_Menu.
  89. *
  90. *    LAWN_MenuTags (struct TagItem *) - A list of TagItems which
  91. *        will get passed straight through to LT_NewMenuTagList().
  92. *        Even if you don't ask for it, LT_Build() will pass
  93. *        "LAMN_Handle,<Handle>" in for you, so any additional tags
  94. *        specifying screen, fonts, etc. will be overridden. If a menu
  95. *        could be created, it will be attached to the window.
  96. *        LT_DeleteHandle() will then later automatically dispose of the
  97. *        menu. Please note that the window may fail to open due to the
  98. *        menu layout going wrong. Separate calls to LT_NewMenuTagList()
  99. *        and LT_Build() may be a better approach since it is easier to
  100. *        find out which process went wrong. You will find a pointer to the
  101. *        menu attached to the LayoutHandle in LayoutHandle->Menu. Please note
  102. *        that this entry only exists in LayoutHandles created by
  103. *        gtlayout.library v13 or higher. (V13)
  104. *
  105. *            NOTE: This tag effectively overrides LAWN_Menu and has
  106. *                  precedence over LAWN_MenuTemplate.
  107. *
  108. *    LAWN_UserPort (struct MsgPort *) - The MsgPort to use as the
  109. *        window user port. The MsgPort will be attached using the
  110. *        common ModifyIDCMP() method, closing the window will
  111. *        first remove and reply all pending messages at this port.
  112. *
  113. *    LAWN_Left (LONG) - The left edge position the window is to use.
  114. *        This effectively overrides any horizontal alignment flags.
  115. *
  116. *            NOTE: the code may choose to ignore this value if it finds
  117. *                that the window will not fit onto the screen unless
  118. *                the left edge position is changed.
  119. *
  120. *    LAWN_Top (LONG) - The top edge position the window is to use.
  121. *        This effectively overrides any vertical alignment flags.
  122. *
  123. *            NOTE: the code may choose to ignore this value if it finds
  124. *                that the window will not fit onto the screen unless
  125. *                the top edge position is changed.
  126. *
  127. *    LAWN_Zoom (BOOL) - Adds a zoom gadget to the window. Clicking
  128. *        on this gadget will cause the window to shrink/zoom back
  129. *        to its original position. This differs from the WA_Zoom
  130. *        tag behaviour. When the window zooms back to its original
  131. *        position the gadgets are automatically refreshed.
  132. *        Default: FALSE
  133. *
  134. *    LAWN_MaxPen (LONG) - The maximum rendering pen index your code
  135. *        will use. Since you are -- with some restrictions -- allowed
  136. *        to render into the window created you may want to avoid
  137. *        silly side effects if drawing images or other colourful
  138. *        textures which do not share the common user interface colours.
  139. *        By default the layout code will change the maximum rendering
  140. *        pen number for the window to include only the user interface
  141. *        pen colours. This can, but need not disturb your own private
  142. *        window rendering.
  143. *        Look up graphics.library/SetMaxPen for more information.
  144. *        Default: determined by looking up Screen->DrawInfo.dri_Pens
  145. *
  146. *    LAWN_BelowMouse (BOOL) - This instructs the layout routine to
  147. *        centre the window created -- if possible -- below the
  148. *        mouse pointer. This effectively ignores any left edge,
  149. *        top edge or alignment settings.
  150. *        Default: FALSE
  151. *
  152. *    LAWN_MoveToWindow (BOOL) - When the window is finally open the
  153. *        user interface code will try to make sure the entire window
  154. *        is visible on the screen, this may involve moving the
  155. *        currently visible portion of an autoscrolling screen.
  156. *        Default: TRUE
  157. *
  158. *    LAWN_AutoRefresh (BOOL) - Handle IDCMP_REFRESHWINDOW events
  159. *        automatically.
  160. *        Default: TRUE
  161. *
  162. *    LAWN_HelpHook (struct Hook *) - Hook code to invoke when the user
  163. *        presses the "Help" key. See gtlayout.h for more information.
  164. *        Default: NULL
  165. *
  166. *    LAWN_Parent (struct Window *) - Parent window to centre the child
  167. *        window in.
  168. *        Default: NULL
  169. *
  170. *    LAWN_BlockParent (BOOL) - Lock the parent window via LT_LockWindow()
  171. *        until the child window is closed.
  172. *
  173. *            NOTE: requires LAWN_Parent attribute.
  174. *
  175. *        Default: FALSE
  176. *
  177. *    LAWN_SmartZoom (BOOL) - Attach a zoom gadget to the window created.
  178. *        When in zoomed state, the window will be as small as possible,
  179. *        showing only the window title and window gadgets:
  180. *
  181. *            NOTE: this tag implies LAWN_Zoom,TRUE
  182. *
  183. *        Default: FALSE
  184. *
  185. *    LAWN_Title (STRPTR) - The window title to use. Use this tag in
  186. *        place of WA_Title or you will break the layout code.
  187. *        Default: no title
  188. *
  189. *    LAWN_Bounds (struct IBox *) - Bounds to centre the window in.
  190. *        Default: NULL
  191. *
  192. *    LAWN_ExtraWidth (LONG) - Extra width to add into the calculation
  193. *        when opening the window.
  194. *        Default: 0
  195. *
  196. *    LAWN_ExtraHeight (LONG) - Extra height to add into the calculation
  197. *        when opening the window.
  198. *        Default: 0
  199. *
  200. *    LAWN_IDCMP (ULONG) - Use this tag in place of WA_IDCMP or you
  201. *        will break the object handling code.
  202. *
  203. *    LAWN_AlignWindow (UWORD) - Alignment information for the window, must
  204. *        be a mask made from the following bit values:
  205. *
  206. *            ALIGNF_RIGHT - Align to screen right edge
  207. *            ALIGNF_LEFT - Align to screen left edge
  208. *            ALIGNF_TOP - Align to screen top edge
  209. *            ALIGNF_BOTTOM - Align to screen bottom edge
  210. *
  211. *        Unless forbidden (such as by passing ALIGNF_RIGHT|ALIGNF_TOP)
  212. *        the window will be centered horizontally and/or vertically.
  213. *
  214. *    LAWN_FlushLeft (BOOL) - Add no horizontal space surrounding the
  215. *        objects the windows will hold. (V10)
  216. *
  217. *    LAWN_FlushTop (BOOL) - Add no vertical space surrounding the
  218. *        objects the windows will hold. (V10)
  219. *
  220. *    LAWN_Show (BOOL) - Make the window visible when it is opened;
  221. *        this may involve depth-arranging screens. (V10)
  222. *           Default: FALSE
  223. *
  224. *    LAWN_NoInitialRefresh (BOOL) - If set to TRUE, adds the
  225. *        gadgets, but does not draw the window imagery. You need
  226. *        to draw them later by calling gtlayout.library/LT_Refresh.
  227. *        Default: FALSE
  228. *
  229. *    LAWN_LimitWidth (UWORD) - Limit the width of the window to this
  230. *        value. (V35)
  231. *
  232. *    LAWN_LimitHeight (UWORD) - Limit the height of the window to this
  233. *        value. (V35)
  234. *
  235. *    LAWN_UserData (APTR) - Store this pointer with the Window information.
  236. *        you can later retrieve it with the LT_GetWindowUserData()
  237. *        call (V39).
  238. *
  239. *   RESULT
  240. *    Window - Pointer to a Window structure.
  241. *
  242. *   SEE ALSO
  243. *       gtlayout.library/LT_Refresh
  244. *       gtlayout.library/LT_GetWindowUserData
  245. *       intuition.library/OpenWindow
  246. *       intuition.library/OpenWindowTagList
  247. *
  248. ******************************************************************************
  249. *
  250. */
  251.  
  252. struct Window * LIBENT
  253. LT_BuildA(REG(a0) LayoutHandle *handle,REG(a1) struct TagItem *TagParams)
  254. {
  255.     ULONG             OpenWindowTag;
  256.     LONG             left, top, width, height;
  257.     LONG             OldLeft,OldTop,OldRight,OldBottom;
  258.     struct IBox         newBounds;
  259.     struct Menu        *menu;
  260.     struct TagItem    *item;
  261.     LONG             placeLeft;
  262.     LONG             placeTop;
  263.     struct IBox         zoomBox;
  264.     struct IBox        *zoom;
  265.     struct TextFont *font;
  266.     struct TagItem    *NewTags,*Tags;
  267.     struct Window    *Parent;
  268.     STRPTR             title;
  269.     struct IBox        *bounds;
  270.     LONG             extraWidth,
  271.                      extraHeight;
  272.     ULONG             IDCMP;
  273.     LONG             align;
  274.     LONG             MinX,
  275.                      MinY,
  276.                      MaxX,
  277.                      MaxY;
  278.     ULONG             BorderBottom,
  279.                      BorderRight;
  280.     struct Menu        *LocalMenu;
  281.     struct TagItem    *LocalMenuTags;
  282.     struct NewMenu    *LocalMenuTemplate;
  283.     BOOL             SizeGadget,
  284.                      SizeBRight,
  285.                      SizeBBottom;
  286.     BOOL              BlockParent,
  287.                      SmartZoom,
  288.                      MakeVisible;
  289.     BOOL             DontRefresh;
  290.     struct TagItem    *TagList;
  291.     WORD             WithinCounter;
  292.  
  293.     if(!handle)
  294.         return(NULL);
  295.  
  296.     menu                = NULL;
  297.     NewTags                = NULL;
  298.     Parent                = handle->Parent;
  299.     title                = NULL;
  300.     bounds                 = NULL;
  301.     extraWidth            = 0,
  302.     extraHeight            = 0;
  303.     IDCMP                = NULL;
  304.     align                = 0;
  305.     LocalMenu            = NULL;
  306.     LocalMenuTags        = NULL;
  307.     LocalMenuTemplate    = NULL;
  308.     SizeGadget            = FALSE,
  309.     SizeBRight            = FALSE,
  310.     SizeBBottom            = FALSE;
  311.     BlockParent            = handle->BlockParent,
  312.     SmartZoom            = FALSE,
  313.     MakeVisible            = FALSE;
  314.     DontRefresh            = FALSE;
  315.  
  316.     WithinCounter = 0;
  317.  
  318.     memset(&newBounds,0,sizeof(newBounds));    /* Initialize this for the sake of the compiler. */
  319.  
  320.     /* close the outermost layout group, if necessary (V45) */
  321.     if(handle->CloseTopGroup)
  322.     {
  323.         LT_EndGroup(handle);
  324.  
  325.         handle->CloseTopGroup = FALSE;
  326.     }
  327.  
  328.     TagList = (struct TagItem *)TagParams;
  329.     while(item = NextTagItem(&TagList))
  330.     {
  331.         switch(item->ti_Tag)
  332.         {
  333.             case LAWN_LimitWidth:
  334.  
  335.                 WithinCounter |= 1;
  336.                 newBounds.Width = item->ti_Data;
  337.                 break;
  338.  
  339.             case LAWN_UserData:
  340.  
  341.                 handle->WindowUserData = (APTR)item->ti_Data;
  342.                 break;
  343.  
  344.             case LAWN_LimitHeight:
  345.  
  346.                 WithinCounter |= 2;
  347.                 newBounds.Height = item->ti_Data;
  348.                 break;
  349.  
  350.             case LAWN_NoInitialRefresh:
  351.  
  352.                 DontRefresh = item->ti_Data;
  353.                 break;
  354.  
  355.             case LAWN_MenuTemplate:
  356.  
  357.                 LocalMenuTemplate = (struct NewMenu *)item->ti_Data;
  358.                 break;
  359.  
  360.             case LAWN_MenuTags:
  361.  
  362.                 LocalMenuTags = (struct TagItem *)item->ti_Data;
  363.                 break;
  364.  
  365.             case LAWN_FlushLeft:
  366.  
  367.                 handle->FlushLeft = item->ti_Data;
  368.                 break;
  369.  
  370.             case LAWN_FlushTop:
  371.  
  372.                 handle->FlushTop = item->ti_Data;
  373.                 break;
  374.  
  375.             case LAWN_TitleText:
  376.  
  377.                 title = (STRPTR)item->ti_Data;
  378.                 break;
  379.  
  380.             case LAWN_TitleID:
  381.  
  382.                 if(!handle->LocaleHook)
  383.                     return(NULL);
  384.                 else
  385.                     title = (STRPTR)CallHookPkt(handle->LocaleHook,handle,(APTR)item->ti_Data);
  386.  
  387.                 break;
  388.  
  389.             case LAWN_Bounds:
  390.  
  391.                 bounds = (struct IBox *)item->ti_Data;
  392.                 break;
  393.  
  394.             case LAWN_ExtraWidth:
  395.  
  396.                 extraWidth = item->ti_Data;
  397.                 break;
  398.  
  399.             case LAWN_ExtraHeight:
  400.  
  401.                 extraHeight = item->ti_Data;
  402.                 break;
  403.  
  404.             case LAWN_IDCMP:
  405.  
  406.                 IDCMP = item->ti_Data;
  407.                 break;
  408.  
  409.             case LAWN_AlignWindow:
  410.  
  411.                 align = item->ti_Data;
  412.                 break;
  413.         }
  414.     }
  415.  
  416.     if(!bounds && WithinCounter == 3)
  417.     {
  418.         UWORD width,height;
  419.  
  420.         width = newBounds.Width;
  421.         height = newBounds.Height;
  422.  
  423.         LTP_GetDisplayClip(handle->Screen,&newBounds.Left,&newBounds.Top,&newBounds.Width,&newBounds.Height);
  424.         bounds = &newBounds;
  425.  
  426.         bounds->Width = width;
  427.         bounds->Height = height;
  428.     }
  429.  
  430.     #ifdef DO_MENUS
  431.     {
  432.         if(LocalMenuTags)
  433.         {
  434.             if(LocalMenu = LT_NewMenuTags(LAMN_Handle,handle,TAG_MORE,LocalMenuTags))
  435.             {
  436.                 menu = LocalMenu;
  437.                 handle->IDCMP |= IDCMP_MENUPICK;
  438.             }
  439.             else
  440.                 return(NULL);
  441.         }
  442.         else
  443.         {
  444.             if(LocalMenuTemplate)
  445.             {
  446.                 if(LocalMenu = LT_NewMenuTemplate(handle->Screen,handle->TextAttr,handle->AmigaGlyph,handle->CheckGlyph,NULL,LocalMenuTemplate))
  447.                 {
  448.                     menu = LocalMenu;
  449.                     handle->IDCMP |= IDCMP_MENUPICK;
  450.                 }
  451.                 else
  452.                     return(NULL);
  453.             }
  454.         }
  455.     }
  456.     #endif    /* DO_MENUS */
  457.  
  458.     if(!bounds)
  459.     {
  460.         LTP_GetDisplayClip(handle->Screen,&newBounds.Left,&newBounds.Top,&newBounds.Width,&newBounds.Height);
  461.  
  462.         bounds = &newBounds;
  463.     }
  464.  
  465.     left = handle->Screen->WBorLeft;
  466.  
  467.     if(title)
  468.         top = handle->Screen->WBorTop + handle->Screen->Font->ta_YSize + 1;
  469.     else
  470.         top = handle->Screen->WBorTop;
  471.  
  472.     BorderRight        = handle->Screen->WBorRight;
  473.     BorderBottom    = handle->Screen->WBorBottom;
  474.  
  475.     if(handle->ResizeObject != NULL)
  476.     {
  477.         BOOLEAN ResizeX,ResizeY;
  478.  
  479.         /* Note: ResizeObject can either be a LISTVIEW_KIND or a
  480.          *       FRAME_KIND!
  481.          */
  482.         if(handle->ResizeObject->Type == LISTVIEW_KIND)
  483.         {
  484.             ResizeX = handle->ResizeObject->Special.List.ResizeX;
  485.             ResizeY = handle->ResizeObject->Special.List.ResizeY;
  486.         }
  487.         else
  488.         {
  489.             ResizeX = handle->ResizeObject->Special.Frame.ResizeX;
  490.             ResizeY = handle->ResizeObject->Special.Frame.ResizeY;
  491.         }
  492.  
  493.         if(ResizeY)
  494.         {
  495.             BorderBottom = LTP_GetSizeHeight(handle);
  496.         }
  497.         else
  498.         {
  499.             if(ResizeX)
  500.                 BorderRight = LTP_GetSizeWidth(handle);
  501.         }
  502.     }
  503.  
  504.     OldLeft        = left;
  505.     OldRight    = BorderRight;
  506.     OldTop        = top;
  507.     OldBottom    = BorderBottom;
  508.  
  509.     if(!handle->FlushLeft)
  510.     {
  511.         left        += handle->InterWidth;
  512.         BorderRight    += handle->InterWidth;
  513.     }
  514.  
  515.     if(!handle->FlushTop)
  516.     {
  517.         top                += handle->InterHeight;
  518.         BorderBottom    += handle->InterHeight;
  519.     }
  520.  
  521.     LTP_CreateGadgets(handle,bounds,left,top,left + BorderRight,top + BorderBottom);
  522.  
  523.     if(handle->Failed)
  524.         return(NULL);
  525.  
  526.         // In case the font got changed we'll have to redo it all again.
  527.         // Just to be sure, we do it all over again.
  528.  
  529.     left            = OldLeft;
  530.     BorderRight        = OldRight;
  531.     top                = OldTop;
  532.     BorderBottom    = OldBottom;
  533.  
  534.     if(!handle->FlushLeft)
  535.     {
  536.         left        += handle->InterWidth;
  537.         BorderRight    += handle->InterWidth;
  538.     }
  539.  
  540.     if(!handle->FlushTop)
  541.     {
  542.         top                += handle->InterHeight;
  543.         BorderBottom    += handle->InterHeight;
  544.     }
  545.  
  546.     width    = left + handle->TopGroup->Width + BorderRight;
  547.     height    = top + handle->TopGroup->Height + BorderBottom;
  548.  
  549.     if(handle->ResizeObject != NULL)
  550.     {
  551.         LONG GlyphWidth,GlyphHeight;
  552.         BOOLEAN ResizeX,ResizeY;
  553.  
  554.         /* Note: ResizeObject can either be a LISTVIEW_KIND or a
  555.          *       FRAME_KIND!
  556.          */
  557.         if(handle->ResizeObject->Type == LISTVIEW_KIND)
  558.         {
  559.             ResizeX = handle->ResizeObject->Special.List.ResizeX;
  560.             ResizeY = handle->ResizeObject->Special.List.ResizeY;
  561.         }
  562.         else
  563.         {
  564.             ResizeX = handle->ResizeObject->Special.Frame.ResizeX;
  565.             ResizeY = handle->ResizeObject->Special.Frame.ResizeY;
  566.         }
  567.  
  568.         MaxX = MinX = width;
  569.         MaxY = MinY = height;
  570.  
  571.         if(ResizeX)
  572.             MaxX = handle->Screen->Width;
  573.  
  574.         if(ResizeY)
  575.         {
  576.             MaxY = handle->Screen->Height;
  577.  
  578.             SizeBBottom = TRUE;
  579.         }
  580.         else
  581.         {
  582.             SizeBRight = TRUE;
  583.         }
  584.  
  585.         SizeGadget = TRUE;
  586.  
  587.         GlyphWidth    = handle->GlyphWidth;
  588.         GlyphHeight    = handle->GlyphHeight;
  589.  
  590.         if(handle->ResizeObject->Type == LISTVIEW_KIND)
  591.         {
  592.             if(handle->ResizeObject->Special.List.TextAttr != NULL)
  593.             {
  594.                 GlyphWidth    = handle->ResizeObject->Special.List.FixedGlyphWidth;
  595.                 GlyphHeight    = handle->ResizeObject->Special.List.FixedGlyphHeight;
  596.             }
  597.         
  598.             if(handle->ResizeObject->Special.List.MinChars && handle->ResizeObject->Special.List.MinChars < handle->ResizeObject->Chars)
  599.                 MinX -= GlyphWidth * (handle->ResizeObject->Chars - handle->ResizeObject->Special.List.MinChars);
  600.  
  601.             if(handle->ResizeObject->Special.List.MinLines && handle->ResizeObject->Special.List.MinChars < handle->ResizeObject->Lines)
  602.                 MinY -= GlyphHeight * (handle->ResizeObject->Lines - handle->ResizeObject->Special.List.MinLines);
  603.         }
  604.         else
  605.         {
  606.             if(MinX < handle->ResizeObject->Special.Frame.InnerWidth)
  607.                 MinX = handle->ResizeObject->Special.Frame.InnerWidth;
  608.  
  609.             if(MinY < handle->ResizeObject->Special.Frame.InnerHeight)
  610.                 MinY = handle->ResizeObject->Special.Frame.InnerHeight;
  611.         }
  612.     }
  613.     else
  614.     {
  615.         MaxX = MinX = width;
  616.         MaxY = MinY = height;
  617.     }
  618.  
  619.     if(align & ALIGNF_LEFT)
  620.         placeLeft = 0;
  621.     else
  622.     {
  623.         if(align & ALIGNF_RIGHT)
  624.             placeLeft = bounds->Width - (width + extraWidth);
  625.         else
  626.             placeLeft = (bounds->Width - (width + extraWidth)) / 2;
  627.     }
  628.  
  629.     if(align & ALIGNF_TOP)
  630.         placeTop = 0;
  631.     else
  632.     {
  633.         if(align & ALIGNF_BOTTOM)
  634.             placeTop = bounds->Height - (height + extraHeight);
  635.         else
  636.             placeTop = (bounds->Height - (height + extraHeight)) / 2;
  637.     }
  638.  
  639.     if(align & ALIGNF_EXTRA_LEFT)
  640.         placeLeft += extraWidth;
  641.     else
  642.     {
  643.         if(!(align & ALIGNF_EXTRA_RIGHT))
  644.             placeLeft += extraWidth / 2;
  645.     }
  646.  
  647.     if(align & ALIGNF_EXTRA_TOP)
  648.         placeTop += extraHeight;
  649.     else
  650.     {
  651.         if(!(align & ALIGNF_EXTRA_BOTTOM))
  652.             placeTop += extraHeight / 2;
  653.     }
  654.  
  655.     placeLeft    += bounds->Left;
  656.     placeTop    += bounds->Top;
  657.  
  658.     if(placeLeft < 0)
  659.         placeLeft = 0;
  660.  
  661.     if(placeTop < 0)
  662.         placeTop = 0;
  663.  
  664.     zoom = NULL;
  665.  
  666.     handle->AutoRefresh = TRUE;
  667.  
  668.     #ifdef DO_CLONING
  669.     {
  670.         if(handle->CloneExtra)
  671.         {
  672.             placeLeft    = 0;
  673.             placeTop    = handle->CloneExtra->Screen->BarHeight + 1;
  674.  
  675.             zoomBox.Left    = placeLeft;
  676.             zoomBox.Top        = placeTop;
  677.         }
  678.     }
  679.     #endif    /* DO_CLONING */
  680.  
  681.     TagList = (struct TagItem *)TagParams;
  682.  
  683.     while(item = NextTagItem(&TagList))
  684.     {
  685.         switch((ULONG)item->ti_Tag)
  686.         {
  687.             case LA_Menu:
  688.  
  689.                 if(!menu)
  690.                 {
  691.                     handle->IDCMP |= IDCMP_MENUPICK;
  692.  
  693.                     menu = (struct Menu *)item->ti_Data;
  694.                 }
  695.  
  696.                 break;
  697.  
  698.             case LAWN_SmartZoom:
  699.  
  700.                 if(!(SmartZoom = item->ti_Data))
  701.                     break;
  702.  
  703.             case LAWN_Zoom:
  704.  
  705.                 if(item->ti_Data)
  706.                 {
  707.                     if(title && SmartZoom)
  708.                     {
  709.                         STATIC const UWORD WhichTable[3] =
  710.                         {
  711.                             CLOSEIMAGE,
  712.                             ZOOMIMAGE,
  713.                             DEPTHIMAGE
  714.                         };
  715.  
  716.                         LONG     Size = 0,i;
  717.                         LONG     SizeType;
  718.                         Object    *Image;
  719.                         BOOL     GotIt = TRUE;
  720.  
  721.                         if(handle->Screen->Flags & SCREENHIRES)
  722.                             SizeType = SYSISIZE_MEDRES;
  723.                         else
  724.                             SizeType = SYSISIZE_LOWRES;
  725.  
  726.                         for(i = 0 ; i < 3 ; i++)
  727.                         {
  728.                             if(Image = NewObject(NULL,SYSICLASS,
  729.                                 SYSIA_Size,        SizeType,
  730.                                 SYSIA_Which,    WhichTable[i],
  731.                                 SYSIA_DrawInfo, handle->DrawInfo,
  732.                             TAG_DONE))
  733.                             {
  734.                                 ULONG Width;
  735.  
  736.                                 GetAttr(IA_Width,Image,&Width);
  737.  
  738.                                 Size += Width;
  739.  
  740.                                 DisposeObject(Image);
  741.                             }
  742.                             else
  743.                                 GotIt = FALSE;
  744.                         }
  745.  
  746.                         if(GotIt)
  747.                         {
  748.                             Size += 8 + TextLength(&handle->Screen->RastPort,title,strlen(title)) + 8;
  749.  
  750.                             zoomBox.Width = Size;
  751.                         }
  752.                         else
  753.                             zoomBox.Width = width;
  754.                     }
  755.                     else
  756.                         zoomBox.Width = width;
  757.  
  758.                     if(V39)
  759.                     {
  760.                         zoomBox.Left    = -1;
  761.                         zoomBox.Top        = -1;
  762.                     }
  763.                     else
  764.                     {
  765.                         zoomBox.Left    = placeLeft;
  766.                         zoomBox.Top        = placeTop;
  767.                     }
  768.  
  769.                     zoomBox.Height = handle->Screen->WBorTop + handle->Screen->Font->ta_YSize + 1;
  770.  
  771.                     zoom = &zoomBox;
  772.                 }
  773.  
  774.                 break;
  775.  
  776.             case LAWN_UserPort:
  777.  
  778.                 handle->MsgPort = (struct MsgPort *)item->ti_Data;
  779.                 break;
  780.  
  781.             case LAWN_HelpHook:
  782.  
  783.                 handle->HelpHook = (struct Hook *)item->ti_Data;
  784.                 break;
  785.  
  786.             case LAWN_Parent:
  787.  
  788.                 Parent = (struct Window *)item->ti_Data;
  789.                 break;
  790.  
  791.             case LAWN_BlockParent:
  792.  
  793.                 BlockParent = item->ti_Data;
  794.                 break;
  795.  
  796.             case LAWN_BelowMouse:
  797.  
  798.                 if((placeLeft = handle->Screen->MouseX - (width / 2)) < 0)
  799.                     placeLeft = 0;
  800.  
  801.                 if((placeTop = handle->Screen->MouseY - (height / 2)) < 0)
  802.                     placeTop = 0;
  803.  
  804.                 break;
  805.  
  806.             case LAWN_MaxPen:
  807.  
  808.                 handle->MaxPen = (LONG)item->ti_Data;
  809.                 break;
  810.  
  811.             case LAWN_MoveToWindow:
  812.  
  813.                 handle->MoveToWindow = (LONG)item->ti_Data;
  814.                 break;
  815.  
  816.             case LAWN_AutoRefresh:
  817.  
  818.                 handle->AutoRefresh = (LONG)item->ti_Data;
  819.                 break;
  820.  
  821.             case LAWN_Show:
  822.  
  823.                 MakeVisible = item->ti_Data;
  824.                 break;
  825.         }
  826.     }
  827.  
  828.     Tags = (struct TagItem *)TagParams;
  829.  
  830.     if(handle->BackgroundPen && !V39)
  831.     {
  832.         if(NewTags = CloneTagItems(Tags))
  833.         {
  834.             STATIC const Tag Filter[] = { WA_SimpleRefresh,TAG_DONE };
  835.  
  836.             FilterTagItems(NewTags,(Tag *)Filter,TAGFILTER_NOT);
  837.  
  838.             Tags = NewTags;
  839.         }
  840.         else
  841.         {
  842.             #ifdef DO_MENUS
  843.             {
  844.                 LT_DisposeMenu(LocalMenu);
  845.             }
  846.             #endif    /* DO_MENUS */
  847.  
  848.             return(NULL);
  849.         }
  850.     }
  851.  
  852.     if(Parent)
  853.     {
  854.         WORD    Left,Top,Width,Height;
  855.         LONG    MoveLeft,MoveTop,WindowLeft,WindowTop,WindowWidth,WindowHeight;
  856.  
  857.         WindowLeft        = Parent->LeftEdge + Parent->BorderLeft;
  858.         WindowTop        = Parent->TopEdge + Parent->BorderTop;
  859.         WindowWidth        = Parent->Width - (Parent->BorderLeft + Parent->BorderRight);
  860.         WindowHeight    = Parent->Height - (Parent->BorderTop + Parent->BorderBottom);
  861.  
  862.         LTP_GetDisplayClip(Parent->WScreen,&Left,&Top,&Width,&Height);
  863.  
  864.         if((MoveLeft = WindowLeft + (WindowWidth - width) / 2) < 0)
  865.             MoveLeft = 0;
  866.  
  867.         if((MoveTop = WindowTop + (WindowHeight - height) / 2) < 0)
  868.             MoveTop = 0;
  869.  
  870.         if(MoveLeft < Left || MoveLeft + width > Left + Width)
  871.             MoveLeft = -1;
  872.  
  873.         if(MoveTop < Top || MoveTop + height > Top + Height)
  874.             MoveTop = -1;
  875.  
  876.         if(MoveTop != -1 && MoveLeft != -1)
  877.         {
  878.             placeLeft    = MoveLeft;
  879.             placeTop    = MoveTop;
  880.         }
  881.     }
  882.  
  883.     TagList = (struct TagItem *)TagParams;
  884.  
  885.     while(item = NextTagItem(&TagList))
  886.     {
  887.         switch((ULONG)item->ti_Tag)
  888.         {
  889.             case LAWN_Left:
  890.  
  891.                 placeLeft = item->ti_Data;
  892.                 break;
  893.  
  894.             case LAWN_Top:
  895.  
  896.                 placeTop = item->ti_Data;
  897.                 break;
  898.         }
  899.     }
  900.  
  901.     if(BlockParent && Parent)
  902.     {
  903.         LT_LockWindow(Parent);
  904.  
  905.         handle->Parent = Parent;
  906.     }
  907.  
  908.     if(SizeGadget)
  909.         zoom = NULL;
  910.  
  911.     if(handle->Screen == handle->PubScreen)
  912.         OpenWindowTag = handle->WA_ScreenTag;
  913.     else
  914.         OpenWindowTag = WA_CustomScreen;
  915.  
  916.     if(handle->Window = OpenWindowTags(NULL,
  917.         WA_Left,            placeLeft,
  918.         WA_Top,             placeTop,
  919.         WA_Width,            width,
  920.         WA_Height,            height,
  921.         WA_NewLookMenus,    TRUE,
  922.         OpenWindowTag,        handle->Screen,
  923.         WA_MinWidth,        MinX,
  924.         WA_MinHeight,        MinY,
  925.         WA_MaxWidth,        MaxX,
  926.         WA_MaxHeight,        MaxY,
  927.         WA_SizeGadget,        SizeGadget,
  928.         WA_SizeBBottom,        SizeBBottom,
  929.         WA_SizeBRight,        SizeBRight,
  930.         WA_PointerDelay,    TRUE,
  931.         WA_BusyPointer,        TRUE,
  932.  
  933.         zoom ? WA_Zoom : TAG_IGNORE,                        zoom,
  934.         !handle->MsgPort ? WA_IDCMP : TAG_IGNORE,            IDCMP_REFRESHWINDOW | IDCMP_RAWKEY | IDCMP_ACTIVEWINDOW | IDCMP_INACTIVEWINDOW | IDCMP_MOUSEBUTTONS | IDCMP_CHANGEWINDOW | IDCMP | handle->IDCMP,
  935.         title ? WA_Title : TAG_IGNORE,                        title,
  936.         handle->AmigaGlyph ? WA_AmigaKey : TAG_IGNORE,        handle->AmigaGlyph,
  937.         handle->CheckGlyph ? WA_Checkmark : TAG_IGNORE,        handle->CheckGlyph,
  938.         handle->BackgroundPen ? WA_BackFill : TAG_IGNORE,    &handle->BackfillHook,
  939.     TAG_MORE,Tags))
  940.     {
  941.         font = handle->RPort.Font;
  942.  
  943.         handle->RPort = *handle->Window->RPort;
  944.  
  945.         LTP_SetFont(handle,font);
  946.  
  947.         if(V39 && handle->MaxPen > 0)
  948.         {
  949.             SetMaxPen(&handle->RPort,handle->MaxPen);
  950.             SetMaxPen(handle->Window->RPort,handle->MaxPen);
  951.         }
  952.  
  953.         if(NewTags)
  954.         {
  955.             FreeTagItems(NewTags);
  956.             NewTags = NULL;
  957.         }
  958.  
  959.             // It's really that simple...
  960.  
  961.         if(DontRefresh)
  962.             LTP_AddGadgetsDontRefresh(handle);
  963.         else
  964.             LTP_AddGadgets(handle);
  965.  
  966.         handle->Window->UserData = (APTR)handle;
  967.  
  968.         if(handle->MsgPort)
  969.         {
  970.             handle->Window->UserPort = handle->MsgPort;
  971.  
  972.             if(!ModifyIDCMP(handle->Window,IDCMP_CHANGEWINDOW | IDCMP_REFRESHWINDOW | IDCMP_RAWKEY | IDCMP_INACTIVEWINDOW | IDCMP_ACTIVEWINDOW | IDCMP_MOUSEBUTTONS | IDCMP | handle->IDCMP))
  973.             {
  974.                 handle->Window->UserPort = NULL;
  975.  
  976.                 return (NULL);
  977.             }
  978.         }
  979.  
  980.         if(menu)
  981.             SetMenuStrip(handle->Window,menu);
  982.  
  983.         handle->Menu = LocalMenu;
  984.  
  985.         LTP_SelectInitialActiveGadget(handle);
  986.  
  987.         #ifdef DO_CLONING
  988.         {
  989.             if(handle->CloneExtra)
  990.                 ScreenToFront(handle->Window->WScreen);
  991.         }
  992.         #endif
  993.  
  994.         if(V39)
  995.             SetWindowPointerA(handle->Window,NULL);
  996.  
  997.         if(MakeVisible)
  998.             ScreenToFront(handle->Screen);
  999.  
  1000.         if(handle->MoveToWindow || MakeVisible)
  1001.             LTP_MoveToWindow(handle);
  1002.  
  1003.         if((handle->Window->Flags & WFLG_WINDOWACTIVE) && handle->ActiveString && !DontRefresh)
  1004.             LT_Activate(handle,handle->ActiveString->ID);
  1005.     }
  1006.     else
  1007.     {
  1008.         if(handle->Parent)
  1009.         {
  1010.             LT_UnlockWindow(handle->Parent);
  1011.  
  1012.             handle->Parent = NULL;
  1013.         }
  1014.  
  1015.         #ifdef DO_MENUS
  1016.         {
  1017.             LT_DisposeMenu(LocalMenu);
  1018.         }
  1019.         #endif    /* DO_MENUS */
  1020.     }
  1021.  
  1022.     FreeTagItems(NewTags);
  1023.  
  1024.     return(handle->Window);
  1025. }
  1026.  
  1027.  
  1028. /*****************************************************************************/
  1029.  
  1030.  
  1031. VOID
  1032. LTP_SelectInitialActiveGadget(LayoutHandle *Handle)
  1033. {
  1034.     ObjectNode *Node;
  1035.     LONG i;
  1036.  
  1037.     Handle->Previous = NULL;
  1038.  
  1039.     for(i = 0 ; i < Handle->Count ; i++)
  1040.     {
  1041.         if(Handle->GadgetArray[i])
  1042.         {
  1043.             if(GETOBJECT(Handle->GadgetArray[i],Node))
  1044.             {
  1045.                 if(LIKE_STRING_KIND(Node) || (Node->Type == INTEGER_KIND))
  1046.                 {
  1047.                     Handle->Previous = Handle->GadgetArray[i];
  1048.                     break;
  1049.                 }
  1050.             }
  1051.         }
  1052.     }
  1053. }
  1054.  
  1055.  
  1056. /*****************************************************************************/
  1057.  
  1058.  
  1059. struct Window *
  1060. LT_Layout(LayoutHandle *handle,STRPTR title,struct IBox *bounds,LONG extraWidth,LONG extraHeight,ULONG IDCMP,LONG align,...)
  1061. {
  1062.     struct Window *Result;
  1063.     va_list VarArgs;
  1064.  
  1065.     va_start(VarArgs,align);
  1066.  
  1067.     Result = LT_Build(handle,
  1068.         LAWN_Title,            title,
  1069.         LAWN_Bounds,        bounds,
  1070.         LAWN_ExtraWidth,    extraWidth,
  1071.         LAWN_ExtraHeight,    extraHeight,
  1072.         LAWN_IDCMP,            IDCMP,
  1073.         LAWN_AlignWindow,    align,
  1074.     TAG_MORE,(struct TagItem *)VarArgs);
  1075.  
  1076.     va_end(VarArgs);
  1077.  
  1078.     return(Result);
  1079. }
  1080.  
  1081.  
  1082. /*****************************************************************************/
  1083.  
  1084.  
  1085. struct Window * LIBENT
  1086. LT_LayoutA(REG(a0) LayoutHandle *handle,REG(a1) STRPTR title,REG(a2) struct IBox *bounds,REG(d0) LONG extraWidth,REG(d1) LONG extraHeight,REG(d2) ULONG IDCMP,REG(d3) LONG align,REG(a3) struct TagItem *TagParams)
  1087. {
  1088.     struct Window *Result;
  1089.  
  1090.     Result = LT_Build(handle,
  1091.         LAWN_Title,            title,
  1092.         LAWN_Bounds,        bounds,
  1093.         LAWN_ExtraWidth,    extraWidth,
  1094.         LAWN_ExtraHeight,    extraHeight,
  1095.         LAWN_IDCMP,            IDCMP,
  1096.         LAWN_AlignWindow,    align,
  1097.     TAG_MORE,TagParams);
  1098.  
  1099.     return(Result);
  1100. }
  1101.  
  1102.  
  1103. /*****************************************************************************/
  1104.  
  1105.  
  1106. struct Window *
  1107. LT_Build(LayoutHandle *Handle,...)
  1108. {
  1109.     struct Window *Result;
  1110.     va_list VarArgs;
  1111.  
  1112.     va_start(VarArgs,Handle);
  1113.     Result = LT_BuildA(Handle,(struct TagItem *)VarArgs);
  1114.     va_end(VarArgs);
  1115.  
  1116.     return(Result);
  1117. }
  1118.  
  1119.  
  1120. /*****************************************************************************/
  1121.  
  1122.  
  1123. /****** gtlayout.library/LT_GetWindowUserData *******************************
  1124. *
  1125. *   NAME
  1126. *    LT_GetWindowUserData -- Obtain user data information associated
  1127. *        with a Window created by gtlayout.library/LT_Build (V39).
  1128. *
  1129. *   SYNOPSIS
  1130. *    Data = LT_GetWindowUserData(Window,DefaultValue);
  1131. *      D0                         A0        A1
  1132. *
  1133. *    APTR LT_GetWindowUserData(struct Window *,APTR);
  1134. *
  1135. *   FUNCTION
  1136. *    You can tell the build process to store user data with the Window
  1137. *    it creates. This can be used as a replacement for the Window->UserData
  1138. *    pointer information which gtlayout.library uses for itself. If the
  1139. *    Window you pass to this routine was created by gtlayout.library/LT_Build
  1140. *    you will receive the user data pointer you passed in, otherwise the
  1141. *    given default value will be returned.
  1142. *
  1143. *   INPUTS
  1144. *    Window - Pointer to a Window created by gtlayout.library/LT_Build
  1145. *
  1146. *   RESULT
  1147. *    Data - The user data pointer you provided for gtlayout.library/LT_Build
  1148. *        with the LAWN_UserData tag or the default value if no such pointer
  1149. *        was provided or this Window was not created by
  1150. *        gtlayout.library/LT_Build.
  1151. *
  1152. *    DefaultValue - If the window was not created by gtlayout.library/LT_Build
  1153. *        this is the value you will receive as the function result.
  1154. *
  1155. *   SEE ALSO
  1156. *       gtlayout.library/LT_Build
  1157. *
  1158. ******************************************************************************
  1159. *
  1160. */
  1161.  
  1162. APTR LIBENT
  1163. LT_GetWindowUserData(REG(a0) struct Window *Window,REG(a1) APTR DefaultValue)
  1164. {
  1165.     APTR Result;
  1166.  
  1167.     Result = DefaultValue;
  1168.  
  1169.     if(Window != NULL)
  1170.     {
  1171.         if(Window->UserData != NULL && !((ULONG)Window->UserData & 1))
  1172.         {
  1173.             LayoutHandle *Local = (LayoutHandle *)Window->UserData;
  1174.  
  1175.             if(Local->PointBack == Local)
  1176.                 Result = Local->WindowUserData;
  1177.         }
  1178.     }
  1179.  
  1180.     return(Result);
  1181. }
  1182.